﻿///////////////////////////////////////////////////////////////////////////////
// Copyright 2016 lingzimaike@gmail.com
// GPLv2
// Author: lingzimaike
///////////////////////////////////////////////////////////////////////////////

#ifndef PAPA_NET_TCP_SERVER_H_
#define PAPA_NET_TCP_SERVER_H_

#include <string>
#include <vector>
#include <event2/event.h>
#include <event2/listener.h>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <papa/base.h>
#include <papa/thread/mutex.h>
#include <papa/thread/thread.h>

namespace papa {
namespace net {

	class SocketEventHandlerFactory;
	class TcpSocket;

	class TcpServer
	{
	public:
		enum State
		{
			NOT_READY,
			READY,
			RUNNING,
			EXITING,
			EXIT
		};

		TcpServer(SocketEventHandlerFactory* factory);
		~TcpServer(void);

		bool Open(const ::std::string& host, int port, int backlog = 1024, int num_thread = 1);
		void Join(void);
		void Close(void);

	private:
        typedef ::boost::shared_ptr<thread::Thread>	ThreadScopedPtr;
		typedef ::std::vector<ThreadScopedPtr>	ThreadArray;
        typedef ::boost::unordered_map<int, TcpSocket*>	SocketMap;

		friend class TcpSocket;

		void do_close_socket(TcpSocket* sock);
		thread::Thread* find_most_free_thread(void) const;
		thread::Thread* init_io_threads(int num_thread);
		bool start_io_threads(void);

		static void listener_cb(
			struct evconnlistener *listener, 
			evutil_socket_t fd, 
			struct sockaddr *sa, 
			int socklen, 
			void *user_data);
		void OnAccept(int fd, struct sockaddr *sa, int socklen);


		volatile State state_;
		volatile int conn_id_gen_;
		struct evconnlistener* acceptor_;
		::boost::scoped_ptr<SocketEventHandlerFactory> event_handler_factory_;
		ThreadArray thread_array_;
		SocketMap socket_map_;
		thread::Mutex socket_map_lock_;

		PAPA_DISALLOW_COPY_AND_ASSIGN(TcpServer)
	};

}}

#endif // PAPA_NET_TCP_SERVER_H_
